---
title: Dynamic styling
description: How to manage dynamic styling in Panda
---

While Panda is mainly focused on the statically analyzable styles, you might need to handle dynamic styles in your
project.

> We recommend that you **avoid relying on runtime values for your styles** . Consider using recipes, css variables or
> `data-*` attributes instead.

Here are some ways you can handle dynamic styles in Panda:

## Runtime values

Using a value that is not statically analyzable at build-time will not work in Panda due to the inability to determine
the style values.

```tsx filename="App.tsx"
import { useState } from 'react'
import { css } from '../styled-system/css'

const App = () => {
  const [color, setColor] = useState('red.300')

  return (
    <div
      className={css({
        // ❌ Avoid: Panda can't determine the value of color at build-time
        color
      })}
    />
  )
}
```

The example above will not work because Panda can't determine the value of `color` at build-time. Here are some ways to
fix this:

### Using Static CSS

Panda supports a [`staticCss`](/docs/guides/static) option in the config you can use to pre-generate some styles ahead
of time.

```tsx filename="panda.config.ts"
import { defineConfig } from '@pandacss/dev'

export default defineConfig({
  staticCss: {
    css: [
      {
        properties: {
          // ✅ Good: Pre-generate the styles for the color
          color: ['red.300']
        }
      }
    ]
  }
})
```

```tsx filename="Button.tsx"
import { useState } from 'react'
import { styled } from '../styled-system/jsx'

export const Button = () => {
  const [color, setColor] = useState('red.300')

  // ✅ Good: This will work because `red.300` is pre-generated using `staticCss` config
  return <styled.button color={color} />
}
```

### Using `token()`

The `token()` function is generated by Panda and contains an object of all tokens by dot-path, allowing you to query for
token's raw value at runtime.

```tsx filename="App.tsx"
import { useState } from 'react'
import { css } from '../styled-system/css'
import { token } from '../styled-system/tokens'

const Component = props => {
  return (
    <div
      className={css({
        // ✅ Good: Store the value in a CSS custom property
        color: 'var(--color)'
      })}
      style={{
        // ✅ Good: Handle the runtime value in the style attribute
        '--color': token(`colors.${props.color}`)
      }}
    >
      Dynamic color with runtime value
    </div>
  )
}

// App.tsx
const App = () => {
  const [runtimeColor, setRuntimeColor] = useState('pink.300')

  return <Component color={runtimeColor} />
}
```

### Using `token.var()`

You could also directly use the `token.var()` function to get a reference to the underlying CSS custom property for a
given token:

```tsx filename="App.tsx"
import { useState } from 'react'
import { token } from '../styled-system/tokens'

const Component = props => {
  return (
    <div
      style={{
        // ✅ Good: Dynamically generate CSS custom property from the token
        color: token.var(`colors.${props.color}`)
      }}
    >
      Dynamic color with runtime value
    </div>
  )
}

const App = () => {
  const [runtimeColor, setRuntimeColor] = useState('yellow.300')

  return <Component color={runtimeColor} />
}
```

## JSX Style Props

Panda supports forwarding JSX style properties to any element in your codebase.

For example, let's say we create a Card component that accepts a `color` prop:

```tsx filename="Card.tsx"
import { styled } from '../styled-system/jsx'

const Card = props => {
  return <styled.div px="4" py="3" {...props} />
}
```

Then you add more style props to the Card component in a different file:

```tsx filename="App.tsx"
const App = () => {
  return (
    <Card color="blue.300">
      <p>Some content</p>
    </Card>
  )
}
```

As long as all prop-value pairs are statically extractable, Panda will automatically generate the CSS, so avoid using
runtime values:

```tsx filename="App.tsx"
import { useState } from 'react'

const App = () => {
  const [color, setColor] = useState('blue.300')

  // ❌ Avoid: Panda can't determine the value of color at build-time
  return (
    <Card color={color}>
      <p>Some content</p>
    </Card>
  )
}
```

## Property Renaming

Due to the static nature of Panda, you can't rename properties at runtime.

```tsx filename="App.tsx"
import { Circle, CircleProps } from '../styled-system/jsx'

type Props = {
  circleSize?: CircleProps['size']
}

const CustomCircle = (props: Props) => {
  const { circleSize = '3' } = props
  return (
    <Circle
      // ❌ Avoid: Panda can't determine the value of circleSize at build-time
      size={circleSize}
    />
  )
}
```

In this case, you need to use the `size` prop.

### Alternative

As of v0.8, we added a new `{fn}.raw()` method to css, patterns and recipes. This function is an identity function and
only serves as a hint for the compiler to extract the css.

It can be useful, for example, in Storybook args or custom react props.

```tsx filename="App.tsx"
// mark the object as valid css for the extractor
<Button rootProps={css.raw({ bg: 'red.400' })} />
```

```tsx
export const Funky: Story = {
  // mark this as a button recipe usage
  args: button.raw({
    visual: 'funky',
    shape: 'circle',
    size: 'sm'
  })
}
```

### Enhanced `css.raw` spreading

> **Added in v1.6.1**

You can also spread `css.raw` objects within nested selectors and conditions for better style composition:

```tsx filename="App.tsx"
import { css } from '../styled-system/css'

const baseStyles = css.raw({ margin: 0, padding: 0 })
const interactive = css.raw({ cursor: 'pointer', transition: 'all 0.2s' })

const component = css({
  // Spreading in child selectors
  '& p': { ...baseStyles, fontSize: '1rem' },

  // Spreading in nested conditions
  _hover: {
    ...interactive,
    _dark: { ...interactive, color: 'white' }
  }
})
```

## Static expressions

Panda supports static expressions in your styles, as long as they are statically analyzable.

### Static Composition

You can compose different style objects together using the `css.raw()` function.

```tsx filename="App.tsx"
import { css } from 'styled-system/css'

const paragraphSpacingStyle = css.raw({
  '& p': { marginBlockEnd: '1em' }
})

export const proseCss = css.raw({
  '& h1': paragraphSpacingStyle
})
```

This will result in the following CSS:

```css
/* ... */
@layer utilities {
  .\[\&_p\]\:mb_1em p,
  .\[\&_h1\]\:\[\&_p\]\:mb_1em h1 p {
    margin-block-end: 1em;
  }
}
```

### Static Expressions

Panda supports the use of functions to generate the style objects as long they are statically analyzable.

You can only use functions that are defined in the ECMAScript spec such as `Math`, `Object`, `Array`, etc, to support
the evaluation of basic expressions like this:

```ts
import { cva } from '.panda/css'

const getVariants = () => {
  const spacingTokens = Object.entries({
    sm: 'token(spacing.1)',
    md: 'token(spacing.2)'
  })

  // Generate variants programmatically
  const variants = spacingTokens.map(([variant, token]) => [variant, { paddingX: token }])
  return Object.fromEntries(variants)
}

const baseStyle = cva({
  variants: {
    variant: getVariants()
  }
})
```

This will generate the following variants object:

```json
{
  "sm": { "paddingX": "token(spacing.1)" },
  "md": { "paddingX": "token(spacing.2)" }
}
```

And the following CSS

```css
@layer utilities {
  .px_token\(spacing\.1\) {
    padding-inline: var(--spacing-1);
  }

  .px_token\(spacing\.2\) {
    padding-inline: var(--spacing-2);
  }
}
```

## Runtime conditions

Even though we recommend that you first look for better alternatives (such as using
[recipe variants](/docs/concepts/recipes)), you may still occasionally need runtime conditions.

When encountering a runtime condition, Panda will first try to resolve it statically. If it can't, it will fallback to
the generating the corresponding CSS for each possible branches.

```tsx
import { useState } from 'react'
import { css } from '../styled-system/css'
import { Stack } from '../styled-system/jsx'

const App = () => {
  const [isHovered, setIsHovered] = useState(false)

  return (
    <Stack
      color={isHovered ? { _hover: 'red.100' } : 'red.200'}
      _hover={{
        color: { base: 'red.300', md: isHovered ? 'red.400' : undefined }
      }}
    >
      <div className={css({ color: isHovered ? 'red.500' : 'red.600' })} />
    </Stack>
  )
}
```

Since none of the conditions above are statically extractable, Panda will generate css for all possible code path,
resulting in a css that looks like this:

```css
/* ... */
@layer utilities {
  .hover\:text_red\.100:where(:hover, [data-hover]) {
    color: var(--colors-red-100);
  }

  .text_red\.200 {
    color: var(--colors-red-200);
  }

  .hover\:text_red\.300:where(:hover, [data-hover]) {
    color: var(--colors-red-300);
  }

  @media screen and (min-width: 768px) {
    .hover\:md\:text_red\.400:where(:hover, [data-hover]) {
      color: var(--colors-red-400);
    }
  }

  .text_red\.500 {
    color: var(--colors-red-500);
  }

  .text_red\.600 {
    color: var(--colors-red-600);
  }
}
/* ... */
```

## Referenced values

Although you should have your styles inlined most of the time, maybe you want to store a value in a variable and re-use
in multiple places. This should be fine as long as you keep it statically analyzable.

Here's a short list of things to avoid:

- Variables that are not defined in the same file
- Variables resulting from a function call (e.g. `const color = getColor()`)

> If you don't know what value a variable holds with a quick glance, Panda won't be able to either.

```tsx
import { css } from '../styled-system/css'

// ✅ Good: All values are statically extractable
const mainColor = 'red.300'
const sizes = { sm: '12px', md: '16px', '2xl': '42px' }

const App = () => {
  return (
    <div
      className={css({
        color: mainColor,
        fontSize: sizes.md,
        width: sizes['2xl']
      })}
    />
  )
}
```

### Runtime reference on known objects

Using a more complex but still common example :

```tsx
import { useState } from 'react'
import { css } from '../styled-system/css'

const colorByType = {
  primary: 'red.300',
  secondary: 'blue.300',
  tertiary: 'green.300'
}

const Section = () => {
  const [type, setType] = useState('primary')

  // ❌ Avoid: since only "gray.100" is statically extractable here
  // This will not work as expected, the color CSS won't be generated
  return <section className={css({ color: colorByType[type] ?? 'gray.100' })}>❌ Will not be extracted</section>
}
```

Even though `colorByType` is statically analyzable, Panda does not _yet_ support this kind of automatic extraction
fallback. This is the perfect opportunity to use the [recipes](/docs/concepts/recipes).

```tsx
import { useState } from 'react'
import { cva } from '../styled-system/cva'

const sectionRecipe = cva({
  base: { color: 'gray.100' },
  variants: {
    type: {
      primary: { color: 'red.300' },
      secondary: { color: 'blue.300' },
      tertiary: { color: 'green.300' }
    }
  }
})

const Section = () => {
  const [type, setType] = useState('primary')

  // ✅ Good: This will work as expected
  return <section className={sectionRecipe({ type })}>✅ With a recipe</section>
}
```

Not only did you get the same end result, but you also got a more readable and maintainable code !

You can now :

- add more variants to your recipe
- add more properties
- use a shorthand or a condition

All of this with complete type-safety and without having to make drastic changes to the component.

> Note that you can also [integrate this recipe directly into your theme](/docs/concepts/recipes) if you want to only
> generate the CSS that you use, among other things

## Summary

### What you can do

```tsx
// ✅ Good: Conditional styles
<styled.div color={{ base: "red.100", md: "red.200" }} />

// ✅ Good: Arbitrary value
<styled.div color="#121qsd" />

// ✅ Good: Arbitrary selector
<styled.div css={{ "&[data-thing] > span": { color: "red.100" } }} />

// ✅ Good: Runtime value (with config.`staticCss`)
const Button = () => {
  const [color, setColor] = useState('red.300')
  return <styled.button color={color} />
}

// ✅ Good: Runtime condition
<styled.div color={{ base: "red.100", md: isHovered ? "red.200" : "red.300" }} />

// ✅ Good: Referenced value
<styled.div color={mainColor} />

```

### What you can't do

```tsx
// ❌ Avoid: Runtime value (without config.`staticCss`)
const Button = () => {
  const [color, setColor] = useState('red.300')
  return <styled.button color={color} />
}

// ❌ Avoid: Referenced value (not statically analyzable or from another file)
<styled.div color={getColor()} />
<styled.div color={colors[getColorName()]} />
<styled.div color={colors[colorFromAnotherFile]} />

const CustomCircle = (props) => {
  const { circleSize = '3' } = props
  return (
    <Circle
      // ❌ Avoid: Panda can't determine the value of circleSize at build-time
      size={circleSize}
    />
  )
}
```
